#include "stdafx.h"
#include "WorldBuilder.h"
#include "TextureLayer.h"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  

TextureLayer::TextureLayer()
:   envMode(EnvironmentModes::Replace),
    rgbCombiMode(RgbCombinationModes::Modulate),
    alphaCombiMode(AlphaCombinationModes::Modulate),
    owner(NULL), sWrapMode(TextureWrapModes::Repeat),
    tWrapMode(TextureWrapModes::Repeat)
{
}

std::wstring TextureLayer::getName() const 
{ 
    return texture->getName(); 
}

void TextureLayer::setTexture(ref<Texture> tex)
{
    texture = tex;
    notify();
}

Texture* TextureLayer::getTexture() const
{
    return texture.get();
}

void TextureLayer::setEnvMode(EnvironmentMode mode)
{
    envMode = mode;
    notify();
}

void TextureLayer::setRgbCombiMode(RgbCombinationMode rgb)
{
    rgbCombiMode = rgb;
    notify();
}

void TextureLayer::setAlphaCombiMode(AlphaCombinationMode alpha)
{
    alphaCombiMode = alpha;
    notify();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  

void TextureLayer::setBorderColor(const Color& color) 
{
    borderColor = color;
    notify();
}

Color TextureLayer::getBorderColor() const
{
    return borderColor;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  

namespace
{
void checkWrapMode(TextureWrapMode mode)
{
   ASSERT(mode == TextureWrapModes::Repeat 
        || mode == TextureWrapModes::Clamp
        || mode == TextureWrapModes::ClampToEdge 
        || mode == TextureWrapModes::ClampToBorder
        || mode == TextureWrapModes::MirroredRepeat);
}
}

void TextureLayer::setSWrapMode(TextureWrapMode mode)
{
    checkWrapMode(mode);
    sWrapMode = mode;
    notify();
}

void TextureLayer::setTWrapMode(TextureWrapMode mode)
{
    checkWrapMode(mode);    
    tWrapMode = mode;
    notify();
}

TextureWrapMode TextureLayer::getSWrapMode() const
{
    return sWrapMode;
}

TextureWrapMode TextureLayer::getTWrapMode() const
{
    return tWrapMode;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  


EnvironmentMode TextureLayer::getEnvMode() const
{
    return envMode;
}

RgbCombinationMode TextureLayer::getRgbCombiMode() const
{
    return rgbCombiMode;
}

AlphaCombinationMode TextureLayer::getAlphaCombiMode() const
{
    return alphaCombiMode;
}

void TextureLayer::setMaterial(Material* mat)
{
    owner = mat;
    
}

Material* TextureLayer::getMaterial() 
{
    return owner;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  

void TextureLayer::notify()
{
    if(owner)
    {
        owner->notifyManager(MaterialEvent::TextureLayerProperty);
    }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  -  

void TextureLayer::setInRenderContext() const
{
    GLuint texId = getTexture()->getId(); 
    
    glBindTexture(GL_TEXTURE_2D, texId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getSWrapMode());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTWrapMode());
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
                    GL_LINEAR_MIPMAP_LINEAR);

    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, 
                     getBorderColor().to_array());

    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, 
              getEnvMode());

    if(getEnvMode() == EnvironmentModes::Combine)
    {
        // These are parameters that OpenGL allows customizing but we don't
        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

        // Here we allow the same customizations as OpenGL, except for the
        // interpolation mode in which the only possibility we contemplate
        // is that the interpolation weight is 1-texture_alpha
        switch(getRgbCombiMode())
        {
        case RgbCombinationModes::AlphaInterpolation:
            glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE);
            glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
            // fall through
        case RgbCombinationModes::Modulate: 
        case RgbCombinationModes::Replace: 
        case RgbCombinationModes::Add:
        case RgbCombinationModes::AddSigned:
        case RgbCombinationModes::Subtract:
            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, getRgbCombiMode());
            break;
        default:
            ASSERT(false);
        }

        // Here we allow the same customizations as OpenGL, except for the
        // interpolation mode which we simply don't allow
        switch(getAlphaCombiMode())
        {
        case RgbCombinationModes::Modulate: 
        case RgbCombinationModes::Replace: 
        case RgbCombinationModes::Add:
        case RgbCombinationModes::AddSigned:
        case RgbCombinationModes::Subtract:
            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, getAlphaCombiMode());
            break;
        default:
            ASSERT(false);
            break;
        }
    }
}